core: Allow adding related objects to commits
authorColin Walters <walters@verbum.org>
Fri, 11 May 2012 20:23:28 +0000 (16:23 -0400)
committerColin Walters <walters@verbum.org>
Tue, 15 May 2012 01:58:22 +0000 (21:58 -0400)
This will be used to store the set of components.

src/libostree/ostree-core.h
src/libostree/ostree-repo.c
src/libostree/ostree-repo.h
src/ostree/ostree-pull.c
src/ostree/ot-builtin-commit.c

index fd58ee3fe8d74ede089074153232ae3423024708..d3491e5784ae3489588d2396ca33458c7c473235 100644 (file)
@@ -29,6 +29,8 @@ G_BEGIN_DECLS
 
 #define OSTREE_MAX_METADATA_SIZE (1 << 26)
 
+#define OSTREE_MAX_RECURSION (256)
+
 #define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
 
 typedef enum {
index bee08dcadaca3729659a240aa35b425b5b6a2a6c..fcb0a5c9727535511db21b0fe2a50e02831609d9 100644 (file)
@@ -1691,6 +1691,7 @@ ostree_repo_stage_commit (OstreeRepo *self,
                           const char   *subject,
                           const char   *body,
                           GVariant     *metadata,
+                          GVariant     *related_objects,
                           const char   *root_contents_checksum,
                           const char   *root_metadata_checksum,
                           char        **out_commit,
@@ -1712,8 +1713,7 @@ ostree_repo_stage_commit (OstreeRepo *self,
   commit = g_variant_new ("(@a{sv}@ay@a(say)sst@ay@ay)",
                           metadata ? metadata : create_empty_gvariant_dict (),
                           parent ? ostree_checksum_to_bytes_v (parent) : ot_gvariant_new_bytearray (NULL, 0),
-                          g_variant_new_array (G_VARIANT_TYPE ("(say)"),
-                                               NULL, 0),
+                          related_objects ? related_objects : g_variant_new_array (G_VARIANT_TYPE ("(say)"), NULL, 0),
                           subject, body ? body : "",
                           GUINT64_TO_BE (g_date_time_to_unix (now)),
                           ostree_checksum_to_bytes_v (root_contents_checksum),
index 201547772c62111f8619066228a7df936081a28a..3cecffad50c8ef1796488a0fdecb6c665a56cdd0 100644 (file)
@@ -245,6 +245,7 @@ gboolean      ostree_repo_stage_commit (OstreeRepo   *self,
                                         const char   *subject,
                                         const char   *body,
                                         GVariant     *metadata,
+                                        GVariant     *related_objects,
                                         const char   *content_checksum,
                                         const char   *metadata_checksum,
                                         char        **out_commit,
index 766e1cba67a08071d96dfcf6b6950109f841627e..652cff33c2599e381aa9e00255861df4f8eec589 100644 (file)
 
 gboolean verbose;
 gboolean opt_prefer_loose;
+gboolean opt_related;
 
 static GOptionEntry options[] = {
   { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Show more information", NULL },
   { "prefer-loose", 0, 0, G_OPTION_ARG_NONE, &opt_prefer_loose, "Download loose objects by default", NULL },
+  { "related", 0, 0, G_OPTION_ARG_NONE, &opt_related, "Download related commits", NULL },
   { NULL },
 };
 
@@ -666,6 +668,7 @@ fetch_and_store_metadata (OtPullData          *pull_data,
 
 static gboolean
 fetch_and_store_tree_metadata_recurse (OtPullData   *pull_data,
+                                       int           depth,
                                        const char   *rev,
                                        GCancellable *cancellable,
                                        GError      **error)
@@ -678,6 +681,13 @@ fetch_and_store_tree_metadata_recurse (OtPullData   *pull_data,
   ot_lobj GFile *stored_path = NULL;
   ot_lfree char *pack_checksum = NULL;
 
+  if (depth > OSTREE_MAX_RECURSION)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Exceeded maximum recursion");
+      goto out;
+    }
+
   if (!fetch_and_store_metadata (pull_data, rev, OSTREE_OBJECT_TYPE_DIR_TREE,
                                  &tree, cancellable, error))
     goto out;
@@ -726,7 +736,7 @@ fetch_and_store_tree_metadata_recurse (OtPullData   *pull_data,
 
       g_free (tmp_checksum);
       tmp_checksum = ostree_checksum_from_bytes_v (tree_csum);
-      if (!fetch_and_store_tree_metadata_recurse (pull_data, tmp_checksum, cancellable, error))
+      if (!fetch_and_store_tree_metadata_recurse (pull_data, depth+1, tmp_checksum, cancellable, error))
         goto out;
     }
 
@@ -737,15 +747,18 @@ fetch_and_store_tree_metadata_recurse (OtPullData   *pull_data,
 
 static gboolean
 fetch_and_store_commit_metadata_recurse (OtPullData   *pull_data,
+                                         int           depth,
                                          const char   *rev,
                                          GCancellable *cancellable,
                                          GError      **error)
 {
   gboolean ret = FALSE;
   ot_lvariant GVariant *commit = NULL;
+  ot_lvariant GVariant *related_objects = NULL;
   ot_lvariant GVariant *tree_contents_csum = NULL;
   ot_lvariant GVariant *tree_meta_csum = NULL;
   ot_lfree char *tmp_checksum = NULL;
+  GVariantIter *iter = NULL;
 
   if (!fetch_and_store_metadata (pull_data, rev, OSTREE_OBJECT_TYPE_COMMIT,
                                  &commit, cancellable, error))
@@ -763,12 +776,39 @@ fetch_and_store_commit_metadata_recurse (OtPullData   *pull_data,
   
   g_free (tmp_checksum);
   tmp_checksum = ostree_checksum_from_bytes_v (tree_contents_csum);
-  if (!fetch_and_store_tree_metadata_recurse (pull_data, tmp_checksum,
+  if (!fetch_and_store_tree_metadata_recurse (pull_data, depth, tmp_checksum,
                                               cancellable, error))
     goto out;
 
+  if (opt_related)
+    {
+      const char *name;
+      ot_lvariant GVariant *csum_v = NULL;
+
+      if (depth > OSTREE_MAX_RECURSION)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Exceeded maximum recursion");
+          goto out;
+        }
+
+      related_objects = g_variant_get_child_value (commit, 2);
+      iter = g_variant_iter_new (related_objects);
+
+      while (g_variant_iter_loop (iter, "(&s@ay)", &name, &csum_v))
+        {
+          ot_lfree char *checksum = ostree_checksum_from_bytes_v (csum_v);
+
+          if (!fetch_and_store_commit_metadata_recurse (pull_data, depth+1, checksum,
+                                                        cancellable, error))
+            goto out;
+        }
+    }
+
   ret = TRUE;
  out:
+  if (iter)
+    g_variant_iter_free (iter);
   return ret;
 }
 
@@ -1258,7 +1298,8 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error)
     {
       const char *commit = value;
       
-      if (!fetch_and_store_commit_metadata_recurse (pull_data, commit, cancellable, error))
+      if (!fetch_and_store_commit_metadata_recurse (pull_data, 0, commit,
+                                                    cancellable, error))
         goto out;
     }
 
@@ -1286,7 +1327,7 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error)
           if (!ostree_validate_checksum_string (sha256, error))
             goto out;
 
-          if (!fetch_and_store_commit_metadata_recurse (pull_data, sha256, cancellable, error))
+          if (!fetch_and_store_commit_metadata_recurse (pull_data, 0, sha256, cancellable, error))
             goto out;
          
           g_hash_table_insert (updated_refs, g_strdup (ref), g_strdup (sha256));
index add7aa2c7a502a7678d0b423d24394ae8aa48fc0..4fe367481a24ddce61747057da8a7fd0fdc257b5 100644 (file)
@@ -37,6 +37,7 @@ static char *parent;
 static char *branch;
 static char **metadata_strings;
 static char *statoverride_file;
+static char *opt_related_objects_file;
 static gboolean skip_if_unchanged;
 static gboolean tar_autocreate_parents;
 static gboolean no_xattrs;
@@ -59,6 +60,7 @@ static GOptionEntry options[] = {
   { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL },
   { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL },
   { "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &statoverride_file, "File containing list of modifications to make to permissions", "path" },
+  { "related-objects-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_related_objects_file, "File containing newline-separated pairs of (checksum SPACE name) of related objects", "path" },
   { NULL }
 };
 
@@ -115,6 +117,74 @@ parse_statoverride_file (GHashTable   **out_mode_add,
   return ret;
 }
 
+static gboolean
+parse_related_objects_file (GVariant     **out_related_objects,
+                            GCancellable  *cancellable,
+                            GError        **error)
+{
+  gboolean ret = FALSE;
+  gsize len;
+  char **iter = NULL; /* nofree */
+  ot_lhash GHashTable *ret_hash = NULL;
+  ot_lvariant GVariant *ret_related_objects = NULL;
+  ot_lobj GFile *path = NULL;
+  ot_lfree char *contents = NULL;
+  GVariantBuilder builder;
+  gboolean builder_initialized = FALSE;
+  char **lines = NULL;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(say)"));
+  builder_initialized = TRUE;
+
+  path = ot_gfile_new_for_path (opt_related_objects_file);
+
+  if (!g_file_load_contents (path, cancellable, &contents, &len, NULL,
+                             error))
+    goto out;
+  
+  lines = g_strsplit (contents, "\n", -1);
+
+  for (iter = lines; iter && *iter; iter++)
+    {
+      const char *line = *iter;
+      const char *spc;
+      ot_lfree char *name = NULL;
+
+      if (!*line)
+        break;
+
+      spc = strchr (line, ' ');
+      if (!spc)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Malformed related objects file");
+          goto out;
+        }
+
+      name = g_strndup (line, spc - line);
+
+      if (!ostree_validate_checksum_string (spc + 1, error))
+        goto out;
+
+      {
+        GVariant *csum_bytes_v = ostree_checksum_to_bytes_v (spc + 1);
+        g_variant_builder_add (&builder, "(s@ay)", name, csum_bytes_v);
+      }
+    }
+
+  ret_related_objects = g_variant_builder_end (&builder);
+  g_variant_ref_sink (ret_related_objects);
+  builder_initialized = FALSE;
+
+  ret = TRUE;
+  ot_transfer_out_value (out_related_objects, &ret_related_objects);
+ out:
+  if (builder_initialized)
+    g_variant_builder_clear (&builder);
+  g_strfreev (lines);
+  return ret;
+}
+
 static OstreeRepoCommitFilterResult
 commit_filter (OstreeRepo         *self,
                const char         *path,
@@ -155,6 +225,7 @@ ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error)
   ot_lfree char *commit_checksum = NULL;
   ot_lvariant GVariant *parent_commit = NULL;
   ot_lvariant GVariant *metadata = NULL;
+  ot_lvariant GVariant *related_objects = NULL;
   ot_lobj GFile *metadata_f = NULL;
   ot_lfree char *contents_checksum = NULL;
   ot_lobj OstreeMutableTree *mtree = NULL;
@@ -236,6 +307,12 @@ ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error)
         goto out;
     }
 
+  if (opt_related_objects_file)
+    {
+      if (!parse_related_objects_file (&related_objects, cancellable, error))
+        goto out;
+    }
+
   repo = ostree_repo_new (repo_path);
   if (!ostree_repo_check (repo, error))
     goto out;
@@ -390,7 +467,7 @@ ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error)
         }
 
       if (!ostree_repo_stage_commit (repo, branch, parent, subject, body, metadata,
-                                     contents_checksum, root_metadata,
+                                     related_objects, contents_checksum, root_metadata,
                                      &commit_checksum, cancellable, error))
         goto out;